<?php

namespace App\Exceptions;

use App\Common\ApiResponse;
use App\Common\ResponseCode;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;


class Handler extends ExceptionHandler {
    use ApiResponse;

    /**
     * A list of the exception types that are not reported.
     *
     * @var array<int, class-string<Throwable>>
     */
    protected $dontReport = [
        AuthenticationException::class,
        AuthorizationException::class,
        HttpException::class,
        ModelNotFoundException::class,
        TokenMismatchException::class,
        ValidationException::class,
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array<int, string>
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register()
    {

    }

    public function report(Throwable $e)
    {
        if (!config('app.debug')) {
            Log::error(
                sprintf(
                    "%s: %s in %s:%d\r",
                    get_class($e),
                    $e->getMessage(),
                    $e->getFile(),
                    $e->getLine()
                )
            );
        }
    }

    /**
     * @param $request
     * @param Throwable $e
     * @return bool
     */
    public function render($request, Throwable $e)
    {
        $routeArr = explode('/', ltrim($request->getRequestUri(), '/'));


        $routeSystem = $routeArr[0];                //系统名称
        $routeUrl = $routeArr[1];                   //路由地址
        $url = $routeSystem . ' /' . $routeUrl;      //完整路径
        $errInfo = $this->getErrParam($request, $e, $url);
        if ($routeSystem != 'api') {
            return $this->apiResponse([], $e->getCode(), $e->getMessage());
        }
        if ($e instanceof MethodNotAllowedHttpException) {
            return $this->responseAndLog(ResponseCode::INVALID_URI, '请求不被允许', $errInfo);
        } elseif ($e instanceof NotFoundHttpException) {
            return $this->responseAndLog(ResponseCode::INVALID_URI, '请求地址不可用', $errInfo);
        } elseif ($e instanceof QueryException) {
            return $this->responseAndLog(ResponseCode::SERVER_ERROR, '数据库错误', $errInfo, 'error');
        } else {
            return $this->responseAndLog(ResponseCode::SERVER_ERROR, '系统内部错误', $errInfo);
        }

        return parent::render($request, $e);
    }

    /**
     * 错误的详情信息
     * @param $request
     * @param $e
     * @param $url
     * @return array
     */
    public function getErrParam($request, $e, $url)
    {
        //code - 错误code
        //message - 错误信息
        //url - 接口url
        //file - 错误文件
        //line - 错误行数
        //params - 所有参数
        return [
            'code' => $e->getCode(),
            'message' => $e->getMessage(),
            'url' => $url,
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'params' => $request->all(),
        ];
    }

    /**
     * 返回异常
     * @param $code
     * @param $message
     * @param $errInfo
     * @param string $logLevel
     * @return mixed
     */
    public function responseAndLog($code, $message, $errInfo, $logLevel = 'info')
    {
        Log::$logLevel(json_encode($errInfo));
        return $this->apiResponse([], $code, $message);
    }

}
